/**
 * 
 */
package biz.innovasoft.ndb;

import java.io.Serializable;
import java.util.List;

import biz.innovasoft.ndb.index.IndexManager;
import biz.innovasoft.ndb.index.Searcher;
import biz.innovasoft.ndb.index.SearcherResult;
import biz.innovasoft.ndb.query.QueryCriteria;
import biz.innovasoft.ndb.query.Result;
import biz.innovasoft.ndb.query.Tuple;
import biz.innovasoft.ndb.util.IndexUtils;

/**
 * 
 * @author Diego Miranda
 *
 */
public class FindHelper implements Serializable {

	private static final long serialVersionUID = 1102956905193518896L;
	
	private GenericRepository repository;
		
	public FindHelper (GenericRepository repository) {
		this.repository = repository;
	}
	
	public Result find(QueryCriteria query, boolean copy) {
		
		Result result = new Result();
		result.setMaxResults(query.getMaxResults());
		result.setPage(query.getPage()+1);
		
		IndexManager imanager = null;
		if (query.isStricted()) {
			imanager = repository.getIndexManager(query.getCriteriaClass());
		} else {
			imanager = repository.getRootIndexManager(query.getCriteriaClass());
		}
		Searcher searcher = new Searcher(imanager);
		SearcherResult sresult = searcher.searchObject(query);
		if (sresult.size() > 0) {
			result.setTotalHits(sresult.getTotalHits());
			result.setMaxRange(sresult.getMaxRange());
			result.setMinRange(sresult.getMinRange());
			result.addAll(repository.getObjectsByOId(sresult.getOids(), copy));
			return result;
		}
			
		if (sresult.size() == 0 && !canQueryRunWithIndex(query)) {
			if (repository.getConfiguration().getUseTemporalIndex()) {
				return createIndexAndFind(query, copy);
			}	
		}
			
		return result;
	}
	
	public Result createIndexAndFind(
			QueryCriteria query, boolean copy) {

		String qid = query.getQueryCacheId();
		IndexManager imanager = repository.getRepositoryIndexManager().getTemporalIndex(qid);
		if (imanager == null ) {
			
			String[] indexesPath = IndexUtils.getExpressionAttributesAsArray(query
					.getExpressions());
			List<Tuple> objects = repository.getAll(query.getCriteriaClass());
			
			if (indexesPath.length == 0) {
				// TODO: poner valores informativos en este result.
				Result result = new Result ();
				result.addAll(objects);
				return result;
			}
			imanager = repository.getRepositoryIndexManager().createTempIndex( query.getCriteriaClass(), 
					indexesPath, query.getQueryCacheId());
			repository.reindex(imanager);
		}
		
		if (imanager != null) {
			
			Searcher searcher = new Searcher(imanager);
			SearcherResult sresult = searcher.searchObject(query);
			if (sresult.size() > 0) {
				Result result = new Result (true, qid);
				result.setMaxResults(query.getMaxResults());
				result.setPage(query.getPage()+1);
				result.setTotalHits(sresult.getTotalHits());
				result.setMaxRange(sresult.getMaxRange());
				result.setMinRange(sresult.getMinRange());
				result.addAll(repository.getObjectsByOId(sresult.getOids(), copy));
				return result;
			}
			
		}
		return new Result (true, null);
	}
	
	private boolean canQueryRunWithIndex(QueryCriteria criteria) {
		List<String> criteriaAttrs = IndexUtils
				.getExpressionAttributes(criteria.getExpressions());
		if (criteriaAttrs.size() == 0)
			return false;
		IndexManager imanager = repository.getIndexManager(criteria.getCriteriaClass());
		for (String attr : criteriaAttrs) {
			if (!imanager.containsEntry(attr)) {
				return false;
			}
		}
		return true;
	}
	
}
